import * as turf from '@turf/turf';
import * as _ from 'lodash';


class MapToolsDrawGeometryService {
    constructor(map) {
        this.map = map;
        this.lineLayerId = 'out-line-layer';
        this.bboxShape = 'draw-bbox-layer';
        this.CircleLayerId = 'draw-circle-layer';
        this.polygenLayerId = 'draw-poly-layer';
        this.clickPoints = [];
        this.movePoint = null;
        this.endPoint = null;
        this.drawType = 'bbox';
        this.dbclick_callback = undefined;
        this.click_callback = undefined;
        this.mousemove_callback = undefined;
        this.subscriptions = [];
        this.mapInit();
    }

    mapInit() {
        if (!this.map.getLayer(this.lineLayerId)) {
            // 外边线的架子
            this.map.addLayer({
                id: this.lineLayerId,
                type: 'line',
                source: {
                    type: 'geojson',
                    data: null,
                },
                paint: {
                    'line-color': 'rgb(4,159,255)',
                    'line-width': 2,
                    'line-dasharray': [1, 2]
                },
            });
        }
        // 三个图层架子：框选、圈选、多边选
        if (!this.map.getLayer(this.bboxShape)) {
            this.map.addLayer({
                id: this.bboxShape,
                type: 'fill',
                source: {
                    type: 'geojson',
                    data: null,
                },
                paint: {
                    'fill-color': '#109eff',
                    'fill-outline-color': '#1E4DEB',  // #1E4DEB
                    'fill-opacity': 0.2
                }
            });
        }
        if (!this.map.getLayer(this.CircleLayerId)) {
            this.map.addLayer({
                id: this.CircleLayerId,
                type: 'fill',
                source: {
                    type: 'geojson',
                    data: null,
                },
                paint: {
                    'fill-color': '#109eff',
                    'fill-outline-color': '#1E4DEB',
                    'fill-opacity': 0.2
                }
            });
        }
        if (!this.map.getLayer(this.polygenLayerId)) {
            this.map.addLayer({
                id: this.polygenLayerId,
                type: 'fill',
                source: {
                    type: 'geojson',
                    data: null,
                },
                paint: {
                    'fill-color': '#109eff',
                    'fill-outline-color': '#1E4DEB',
                    'fill-opacity': 0.2
                }
            });
        }
    }

    /**
     * @description: 绘制多边形
     *
     * @param {*} type
     * @param {*} doubleClickCallback
     * @param {*} [mouseMoveCallback]
     * @memberof MapToolsDrawGeometryService
     */
    draw(type, doubleClickCallback) {
        this.resetDraw();
        this.drawType = type;
        this.bindDrawEvent(doubleClickCallback);
    }

    bindDrawEvent(doubleClickCallback) {
        const self = this;
        // 取消事件订阅
        self.offMapEvent();
        this.dbclick_callback = (e) => {
            self.map.getCanvas().style.cursor = 'hand';
            self.endPoint = e.lngLat;
            let result = [];
            switch (self.drawType) {
                case 'bbox':
                    result = [self.clickPoints[0], self.endPoint];
                    break;
                case 'circle':
                    result = [self.clickPoints[0], self.endPoint];
                    break;
                case 'polygon':
                    var array = self.clickPoints.slice(0, self.clickPoints.length - 1);
                    result = [
                        // fix: 减少一个的原因：双击操作的第一下实际上还是会执行单击操作，导致多添加一次结束点！
                        ...array,   // 以前添加的点
                        self.clickPoints[0],   // 第一个点。用于围成封闭图形！
                    ];
                    break;
                default:
                    break;
            }
            // 绘制结束时依旧禁止双击放大地图（延迟会儿再放开！）
            this.map.doubleClickZoom.disable();
            self.drawGeoJSON(result);
            self.offMapEvent();
            // 公布出去绘制完成后的GeoJSON
            const geojson = this.arrayToGeoJSON(result)
            doubleClickCallback(geojson);
        };
        this.click_callback = (e) => {
            // fix: 双击操作时，第一下按下鼠标还是会触发点击事件！
            self.clickPoints.push(e.lngLat);
        };
        // 节流处理：鼠标移动
        this.mousemove_callback = _.throttle((e) => {
            self.map.getCanvas().style.cursor = 'crosshair';
            self.movePoint = e.lngLat;
            let coordinates = [];
            if (self.drawType === 'bbox' && self.clickPoints.length > 0) {
                // BBOX;
                coordinates = [self.clickPoints[0], e.lngLat];
                self.drawGeoJSON(coordinates);
            }
            else if (self.drawType === 'polygon') {
                let coordinates = [];
                // tip: 只有一个点时，只绘制线图层，线图层的第二个点是移动点。
                if (self.clickPoints.length === 1) {
                    coordinates = [
                        ...self.clickPoints,
                        self.movePoint
                    ];
                }
                // tip: 当有两个固定点时，要绘制线、面图层；加上移动中的这个点，就构成了三个点，再加上起始点就可以绘制面了。
                if (self.clickPoints.length >= 2) {
                    coordinates = [
                        ...self.clickPoints,
                        self.movePoint,
                        self.clickPoints[0]
                    ];
                }
                self.drawGeoJSON(coordinates);
            }
            else if (self.drawType === 'circle' && self.clickPoints.length > 0) {
                // 绘制圆！
                coordinates = [self.clickPoints[0], e.lngLat];
                self.drawGeoJSON(coordinates); // 公布出去的是图形绘制必须的点！
            }
        }, 200);
        self.openMapEvent();
    }

    /**
     * 打开地图事件监听
     *
     * @memberof MapToolsDrawGeometryService
     */
    openMapEvent() {
        if (this.dbclick_callback) {
            this.map.on('dblclick', this.dbclick_callback);
        }
        if (this.click_callback) {
            this.map.on('click', this.click_callback);
        }
        if (this.mousemove_callback) {
            this.map.on('mousemove', this.mousemove_callback);
        }
    }

    /**
     * @description: 绘制得到GeoJson后进行上图！
     *
     * @param {Array<Point>} points
     * @memberof MapToolsDrawGeometryService
     */
    drawGeoJSON(points) {
        let geoJson = this.arrayToGeoJSON(points);
        if (this.drawType === 'polygon') {
            if (points.length >= 1 && points.length < 3) {
                this.map.getSource(this.lineLayerId).setData(geoJson);
            }
            if (points.length >= 3) {
                this.map.getSource(this.lineLayerId).setData(geoJson);
                this.map.getSource(this.polygenLayerId).setData(geoJson);
            }
        }
        if (this.drawType === 'bbox') {
            this.map.getSource(this.lineLayerId).setData(geoJson);
            if (points.length >= 2) {
                this.map.getSource(this.bboxShape).setData(geoJson);
            }
        }
        if (this.drawType === 'circle') {
            this.map.getSource(this.lineLayerId).setData(geoJson);
            if (points.length >= 2) {
                this.map.getSource(this.CircleLayerId).setData(geoJson);
            }
        }
        setTimeout(() => {
            this.map.getCanvas().style.cursor = 'grab';
            this.map.doubleClickZoom.enable();
        }, 500);
    }

    /**
     * 收集到点集合，转换成GeoJson
     *
     * @private
     * @param {Array<any>} Points
     * @return {*} 
     * @memberof MapToolsDrawGeometryService
     */
    arrayToGeoJSON(Points) {
        const colloction = [];
        Points.forEach((point) => {
            const { lng, lat } = point;
            colloction.push([lng, lat]);
        });
        switch (this.drawType) {
            case 'bbox':
                var bbox = [colloction[0][0], colloction[0][1], colloction[1][0], colloction[1][1]];
                return turf.bboxPolygon(bbox);
            case 'circle':
                var center = colloction[0]; // 计算中心点！
                var line = turf.lineString(colloction);
                var radius = turf.length(line, { units: 'kilometers' }); // 计算半径
                // const options: any = { steps: 64, units: 'kilometers', properties: { foo: 'bar' } };
                // return turf.circle(center, radius, options); // 获取图形！
                return this.createGeoJSONCircle(center, radius); // 获取图形！
            case 'polygon':
                if (Points.length >= 2 && Points.length < 3) {
                    return turf.lineString(colloction);
                } else if (Points.length >= 3) {
                    return turf.polygon([colloction]);
                } else {
                    return null;
                }
            default:
                break;
        }
        return null;
    }

    /** 获得正圆 */
    createGeoJSONCircle(center, radiusInKm, points) {
        if (!points) points = 14;

        const coords = {
            latitude: center[1],
            longitude: center[0],
        };

        const km = radiusInKm;

        let ret = [];
        const distanceX = km / (111.320 * Math.cos((coords.latitude * Math.PI) / 180));
        const distanceY = km / 95.574;

        let theta, x, y;
        for (let i = 0; i < points; i++) {
            theta = (i / points) * (2 * Math.PI);
            x = distanceX * Math.cos(theta);
            y = distanceY * Math.sin(theta);
            ret.push([coords.longitude + x, coords.latitude + y]);
        }
        ret.push(ret[0]);

        return {
            type: 'Feature',
            geometry: {
                type: 'Polygon',
                coordinates: [ret],
            },
        };
    }

    /**  重置draw */
    resetDraw() {
        this.clickPoints = [];
        this.movePoint = null;
        this.endPoint = null;

        this.clearSource();
        this.offMapEvent();  // 关闭监听！
        this.map.getCanvas().style.cursor = 'hand';  // 修改鼠标手势
    }

    /** 关闭绘制事件 */
    offMapEvent() {
        if (this.dbclick_callback) {
            this.map.off('dblclick', this.dbclick_callback);
        }
        if (this.click_callback) {
            this.map.off('click', this.click_callback);
        }
        if (this.mousemove_callback) {
            this.map.off('mousemove', this.mousemove_callback);
        }
    }

    /**
     * 清空各个绘制图层的source（题外话，和这里无关：mapbox规则-图层存在的情况下无法清除source。必须先移除图层）
     *
     */
    clearSource() {
        if (this.map.getSource(this.lineLayerId)) {
            this.map.getSource(this.lineLayerId).setData({
                type: 'FeatureCollection',
                features: [],
            });
        }
        if (this.map.getSource(this.bboxShape)) {
            this.map.getSource(this.bboxShape).setData({
                type: 'FeatureCollection',
                features: [],
            });
        }
        if (this.map.getSource(this.CircleLayerId)) {
            this.map.getSource(this.CircleLayerId).setData({
                type: 'FeatureCollection',
                features: [],
            });
        }
        if (this.map.getSource(this.CircleLayerId)) {
            this.map.getSource(this.polygenLayerId).setData({
                type: 'FeatureCollection',
                features: [],
            });
        }
    }
}

export { MapToolsDrawGeometryService };